package pers.xiaojun.boot.file.core.client;


import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import pers.xiaojun.boot.common.biz.infra.file.FileConfigApi;
import pers.xiaojun.boot.common.biz.infra.file.dto.FileConfigRespDTO;
import pers.xiaojun.boot.common.biz.system.dict.DictCommonApi;
import pers.xiaojun.boot.common.util.CacheUtils;
import pers.xiaojun.boot.common.util.JsonUtils;
import pers.xiaojun.boot.file.core.enums.FileStorageEnum;

import java.time.Duration;

/**
 * 文件客户端工厂实现类
 *
 * @author xiaojun
 * @since 2025-11-15
 */
@RequiredArgsConstructor
public class FileClientFactoryImpl implements FileClientFactory {


    private static final FileConfigApi fileConfigApi;
    private static LoadingCache<Long, FileClient> clientCache;

    static {
        fileConfigApi = SpringUtil.getBean(FileConfigApi.class);
        clientCache = buildClientCache();
    }

    private static LoadingCache<Long, FileClient> buildClientCache() {
        return CacheUtils.buildAsyncReloadingCache(Duration.ofSeconds(10), new CacheLoader<>() {
            @Override
            public FileClient load(Long key) {
                FileConfigRespDTO fileConfig = fileConfigApi.getFileConfigById(key);
                return getSelf().createFileClient(
                        fileConfig.getId(),
                        fileConfig.getStorage(),
                        JsonUtils.fromJson(fileConfig.getConfigJson(), FileClientConfig.class)
                );
            }
        });
    }


    /**
     * 创建文件客户端
     *
     * @param configId     配置Id
     * @param storage      存储类型枚举
     * @param clientConfig 客户端配置
     * @param <Config>     配置类型，如 S3
     * @return 客户端
     */
    @SuppressWarnings("unchecked")
    @Override
    public <Config extends FileClientConfig> AbstractFileClient<Config> createFileClient(Long configId, Integer storage, FileClientConfig clientConfig) {
        FileStorageEnum storageEnum = FileStorageEnum.getByStorage(storage);
        Assert.notNull(storageEnum, String.format("文件配置 (%s) 为空", storageEnum));

        AbstractFileClient<Config> fileClient = (AbstractFileClient<Config>) ReflectUtil.newInstance(storageEnum.getClientClass(), configId, clientConfig);
        fileClient.init();

        return fileClient;
    }

    @Override
    @SneakyThrows
    public FileClient getFileClient(Long configId) {
        return clientCache.get(configId);
    }


    /**
     * 获取IoC容器中的本身
     */
    private static FileClientFactory getSelf() {
        return SpringUtil.getBean(FileClientFactory.class);
    }
}
